package com.easyJava.builder;

import com.easyJava.bean.Constants;
import com.easyJava.bean.FieldInfo;
import com.easyJava.bean.TableInfo;
import com.easyJava.utils.BufferedWriterUtils;
import com.easyJava.utils.StringUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ArrayUtils;

import java.io.*;
import java.nio.charset.StandardCharsets;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

@Slf4j
public class BuildMapper {
    public static void execute(TableInfo tableInfo){
        File folder = new File(Constants.PATH_MAPPER);
        folder.mkdirs();
        String mapperName = tableInfo.getBeanName() + Constants.SUFFIX_MAPPER;

        File file = new File(folder, mapperName + Constants.FILE_SUFFIX_JAVA);

        try (
                OutputStream out = new FileOutputStream(file);
                OutputStreamWriter ow = new OutputStreamWriter(out, StandardCharsets.UTF_8);
                BufferedWriter bufferedWriter = new BufferedWriter(ow);
        ){
            BufferedWriterUtils bw = new BufferedWriterUtils(bufferedWriter);

            //生成包头
            bw.write("package " + Constants.PACKAGE_MAPPER + ";");
            bw.newLine();

            //引入时间或浮点数类
            importRequirePackage(tableInfo, bw);

            //引入泛型引用类
            bw.write("import " + Constants.PACKAGE_PO + "." + tableInfo.getBeanName() + ";");
            bw.write("import " + Constants.PACKAGE_QUERY + "." + tableInfo.getBeanQueryName() + ";");
            bw.write("import org.apache.ibatis.annotations.Param;");
            bw.newLine();

            //生成注解
            BuildComment.createClassComment(bw, tableInfo.getComment() + Constants.SUFFIX_MAPPER);
            //Mapper接口
            bw.write("public interface " + mapperName + " extends BaseMapper<"+ tableInfo.getBeanName() + ", " + tableInfo.getBeanQueryName() +"> {");
            //根据唯一索引生成删改查方法
            generateMethodByUniqueIndex(tableInfo, bw);

            bw.write("}");
            bw.flush();
        }catch (Exception e){
            log.error("创建mapper失败:{}", e);
        }

    }

    private static void generateMethodByUniqueIndex(TableInfo tableInfo, BufferedWriterUtils bw) throws IOException {
        Map<String, List<FieldInfo>> indexMap = tableInfo.getIndexMap();
        for(Map.Entry<String, List<FieldInfo>> entry : indexMap.entrySet()){
            List<FieldInfo> fieldInfoList = entry.getValue();
            StringBuffer methodNameSB = new StringBuffer();
            StringBuffer paramSB = new StringBuffer();
            int index = 0;
            for(FieldInfo fieldInfo : fieldInfoList){
                index++;
                methodNameSB.append(StringUtils.upperFirstChar(fieldInfo.getBeanFieldName()));
                if(index < fieldInfoList.size()){
                    methodNameSB.append("And");
                }
                paramSB.append("@Param(\"" + fieldInfo.getBeanFieldName() + "\") " + fieldInfo.getJavaType() + " " +  fieldInfo.getBeanFieldName());
                if(index < fieldInfoList.size()){
                    paramSB.append(", ");
                }
            }
            String methodName = methodNameSB.toString();
            String param = paramSB.toString();

            BuildComment.createMethodComment(bw, "根据" + methodName + "查询");
            bw.write("\t" + tableInfo.getBeanName() + " selectBy" + methodName + "(" + param + ");");
            bw.newLine();

            BuildComment.createMethodComment(bw, "根据" + methodName + "修改");
            bw.write("\tint" + " updateBy" + methodName + "(" + "@Param(\"bean\") " + tableInfo.getBeanName() + " " + StringUtils.lowerFirstChar(tableInfo.getBeanName()) + ", " + param + ");");
            bw.newLine();

            BuildComment.createMethodComment(bw, "根据" + methodName + "删除");
            bw.write("\tint" + " deleteBy" + methodName + "(" + param + ");");
            bw.newLine();
        }
    }

    private static void importRequirePackage(TableInfo tableInfo, BufferedWriterUtils bw) throws IOException {
        Set<String> sqlTypes = new HashSet<>();
        for(Map.Entry<String, List<FieldInfo>> entry : tableInfo.getIndexMap().entrySet()){
            for(FieldInfo fieldInfo : entry.getValue()){
                sqlTypes.add(fieldInfo.getSqlType());
            }
        }
        for(String sqlType : Constants.SQL_DATE_TYPE){
            if(sqlTypes.contains(sqlType)){
                bw.write("import java.time.LocalDate;");
            }
        }
        for(String sqlType : Constants.SQL_DATE_TIME_TYPE){
            if(sqlTypes.contains(sqlType)){
                bw.write("import java.time.LocalDateTime;");
            }
        }
        for(String sqlType : Constants.SQL_DECIMAL_TYPE){
            if(sqlTypes.contains(sqlType)){
                bw.write("import java.math.BigDecimal;");
            }
        }
    }
}

